/* -*-C-*-
 ##############################################################################
 #
 # File:        trice/src/machine.c
 # RCS:         "@(#)$Revision: 1.21 $ $Date: 94/03/15 17:05:10 $"
 # Description: Routines that are machine dependent
 # Author:      Doug Passey
 # Created:     
 # Language:    C
 # Package:     E1430
 # Status:      "@(#)$State: Exp $"
 #
 # (C) Copyright 1992, Hewlett-Packard Company, all rights reserved.
 #
 ##############################################################################
 #
 # Please add additional comments here
 #
 # Revisions:
 #
 ##############################################################################
*/

#include "machType.h"

#    include <stdio.h>
#    include <string.h>
#    include <time.h>
#    ifndef DOS_OS
#      include <unistd.h>
#    endif
#    ifndef RADISYS
#      include <signal.h>
#    endif
#    include <malloc.h>
#    ifdef _WINDLL
#      include <windows.h>
#    endif
#  ifdef RADISYS 
#    include <busmgr.h>
#  endif
#  if defined(_HPUX_SOURCE) || defined(DOS_OS)
#    ifdef EMULATE_SICL
#      include "sicl_e.h"
#    else
#      include <sicl.h>
#    endif
#  endif


#include "trice.h"
#include "err1430.h"

#ifndef lint
extern const char _e1430BuildId1[];
extern const char _e1430BuildId2[];
const char machine_fileId[] = "$Header: machine.c,v 1.21 94/03/15 17:05:10 chriss Exp $";
static const char *libid1 = _e1430BuildId1;
static const char *libid2 = _e1430BuildId2;
#endif

#define MAX_LOGICAL_ADDRS	256

/******************************************************************************
 *
 * Malloc memory
 *
 *****************************************************************************/
void *i1430_get_mem(ULONGSIZ32 size)
{
#  ifdef DOS_OS
     return(malloc( (size_t)size ));
#  else
     return(malloc(size));
#  endif
}



/******************************************************************************
 *
 * Free memory
 *
 *****************************************************************************/
void i1430_free_mem(void *memPtr)
{
  /* don't free null pointer to avoid E1485 warnings. */
  if (memPtr) {
      free(memPtr);
  }
}



#ifndef RADISYS
/******************************************************************************
 *
 * This is the bus error handler to catch bus error due to read and writes
 * to non-existant registers on the VXI bus.
 *
 *****************************************************************************/
static void bus_error_handler(LONGSIZ32 sig, LONGSIZ32 code, struct sigcontext *scp)
{
  if (sig==SIGBUS) {
    longjmp(e1430_env,1); 		/* return to previous context */
  }else{
    (void)printf("Illegal signal value to bus_error_handler():  Signal = %d\n", sig);
    exit(-1);
  }
}



/******************************************************************************
 *
 * This turns the TRY-RECOVER mechanism on and off.
 *
 *****************************************************************************/
void e1430_set_try_recover(LONGSIZ32 state)
{ 
  struct sigvec vec;

  e1430_try = state;
 
  if(state) {		/* reestablish sig vector */
    vec.sv_handler = bus_error_handler;
    vec.sv_mask = 0;
    vec.sv_flags = 0;

    (void)sigvector(SIGBUS, &vec, &vec);	/* install bus error handler */
  }
}

#endif	/* RADISYS */

#ifdef RADISYS
/******************************************************************************
 *
 * Clear the "stickey bus error" bit in the RadiSys EP7 hardware.
 * When running on the RadiSys hardware, this should be called during
 * "TRY" setup of a try/recover bus-error code.  Return 1 if OK.
 *
 *****************************************************************************/
SHORTSIZ16 e1430_clear_berr(void)
{ 
  SHORTSIZ16 ret;

  /* call a BusManager routine in the RadiSys EPConnect library,  */
  /* using parameters defined in busmgr.h */
  ret = EpcVmeCtrl( CTRL_DEASSERT, VME_STICKY_BERR );
  return ( ret != ERR_FAIL);
}

/******************************************************************************
 *
 * Check the "stickey bus error" bit in the RadiSys EP7 hardware.
 *
 *****************************************************************************/
SHORTSIZ16 e1430_check_berr(void)
{ 
  while( 1 == EpcVmeCtrl( CTRL_READ, VME_PIPELINE_BUSY )) {
	/* wait  for writes to complete */;
  }
  return EpcVmeCtrl( CTRL_READ, VME_STICKY_BERR );
}
#endif

/******************************************************************************
 * This routine performs any initialization needed on the I/O driver.
 *****************************************************************************/
SHORTSIZ16 e1430_init_io_driver(void)
{
#ifndef RADISYS
     struct sigvec vec;
#endif
  char buf1[80]; 

  /* initialize global variables */
  e1430_printFlag = 0;
  e1430_returnError = 1;
  e1430_debug = 0;
  e1430_try = 1;
  e1430_timeout = TRICE_TIMEOUT;
  e1430_modGroupID = NULL;
  e1430_modGroupIdSize = 0;
  e1430_modStates = NULL;
  e1430_modStatesSize = 0;
  e1430_groupID = 0;
  e1430_la = -1;
  e1430_device_clear_flag = 0;

  i1430_clear_masters_array();

#  ifndef RADISYS
     vec.sv_handler = bus_error_handler;
     vec.sv_mask = 0;
       vec.sv_flags = 0;
     (void)sigvector(SIGBUS, &vec, &vec); /* install bus error handler */
#  endif

  (void)strcpy(buf1, "vxi");
  e1430_sicl_id = iopen(buf1);

  if(e1430_sicl_id == (INST)NULL) {
    return(i1430_Error(ERR1430_UNABLE_TO_OPEN_SICL, buf1, NULL));
  }

  e1430_baseAddr = (SHORTSIZ16 *)imap(e1430_sicl_id, I_MAP_A16, 0, 0, NULL); 

  if(e1430_baseAddr == NULL) {
    return (i1430_Error(ERR1430_UNABLE_TO_MAP_MEMORY, NULL, NULL));
  }else{
    return (0);
  }
}


/******************************************************************************
 * This routine returns the address of a register on the E1430 module whose
 * logical address is la, and whose register offset is regOffset.   
 *****************************************************************************/
SHORTSIZ16 *e1430_get_register_address(SHORTSIZ16 la, SHORTSIZ16 regOffset)
{
  return (SHORTSIZ16 *)((char *)e1430_baseAddr + (64 * la) + regOffset + 0xC000);
}

/******************************************************************************
 *
 * This function returns in <slot> and <cage> the slot number and mainframe
 * number at which the module at logical address <la> resides.
 *
 *****************************************************************************/
SHORTSIZ16 i1430_get_slot_and_cage(SHORTSIZ16 la, SHORTSIZ16 *slot, SHORTSIZ16 *cage)
{
/* this broke on s700 and isn't used anywhere in library; so it is disabled.
 */
  *cage = 0;
  *slot = la;
  return (0);
#if 0
      struct vxiinfo info;
      SHORTSIZ16 error; 
      char buf[80];

      error = (SHORTSIZ16)ivxirminfo(e1430_sicl_id, (int)la, &info); 
      if(error) {
	sprintf(buf, "%hd, ivxirminfo() returns error %hd", la, error);
	return (i1430_Error(ERR1430_NO_MOD_AT_LA, buf, NULL));
      }
      
      info.slot = 2;
      info.cage_num = 0;

      *slot = info.slot;
      *cage = info.cage_num;

      return (0);
#endif
}

/*****************************************************************************
 *
 * Gets the current time as a floating point number in seconds.
 *
 * Returns 0 
 *
 *****************************************************************************/
SHORTSIZ16 i1430_get_time(FLOATSIZ64 *secs)
{
#ifdef DOS_OS
#ifndef _WINDLL
    clock_t ticks;

    ticks = clock();
    *secs = (double)ticks / CLOCKS_PER_SEC ;
    return 0;  
#else  /* _WINDLL */
	*secs = (double)GetTickCount() / 1000.0;
	return 0;
#endif /* _WINDLL */	
#else  /* not DOS_OS */
     struct timeval tp;
     struct timezone tz;
     LONGSIZ32 sec, usec;		

     if(0 != gettimeofday(&tp, &tz)) {
       return(i1430_Error(ERR1430_SYSTEM_TIME, NULL, NULL));
     }
     sec = tp.tv_sec;  /* avoid __floatu unresolved external in E1485 */
     usec = tp.tv_usec;
   *secs = sec + 0.000001 * usec;
   return (0);
#endif
}

#define NUM_SYNC_TRIES		100
/*****************************************************************************
 *
 * Wait for the sync line to be valid
 * Returns 0 if OK, error if a timeout
 *
 *****************************************************************************/
SHORTSIZ16 i1430_wait_for_sync_valid(SHORTSIZ16 la)
{
  SHORTSIZ16 i, status, error;
  FLOATSIZ64 startTime, currentTime; 
  LONGSIZ32 timeout;

  for(i=0; i<NUM_SYNC_TRIES; i++) {
    error = e1430_get_status(la, &status);
    if(error) return(error);

    if(status & E1430_MEAS_STATUS_SYNC_VALID) {
      return(0);
    }
  }

  error = i1430_get_time(&startTime);
  if(error) return(error);

  error = e1430_get_timeout(&timeout);
  if(error) return(error);

  do{
    error = e1430_get_status(la, &status);
    if(error) return(error);

    if(status & E1430_MEAS_STATUS_SYNC_VALID) {
      return(0);
    }

    error = i1430_get_time(&currentTime);
    if(error) return(error);

  }while(currentTime - startTime < timeout);

  return (i1430_Error(ERR1430_WAIT_SYNC_TIMEOUT, NULL, NULL));
}


/*****************************************************************************
 *
 * Pause for <time>, where <time> is a floating point number in seconds.
 *
 * Returns 0 
 *
 *****************************************************************************/
SHORTSIZ16 e1430_pause(FLOATSIZ64 secs)
{
  FLOATSIZ64 currentTime, startTime;
  SHORTSIZ16 error;

  error = i1430_get_time(&startTime);
  if(error) return(error);

  while(1) {
    error = i1430_get_time(&currentTime);
    if(error) return(error);

    if(currentTime - startTime > secs) break;
  }
  return (0);
}


/*****************************************************************************
 *
 * Get the length of on system clock tick in seconds.
 *
 * Returns 0 
 *
 *****************************************************************************/
SHORTSIZ16 i1430_get_clock_tick(FLOATSIZ64 *tick)
{
  FLOATSIZ64 currentTime, startTime;
  SHORTSIZ16 error;

  error = i1430_get_time(&startTime);
  if(error) return(error);

  while(1) {
    error = i1430_get_time(&currentTime);
    if(error) return(error);
    if(currentTime != startTime) {
      *tick = currentTime - startTime;
      break;
    }
  }
  return (0);
}


/*****************************************************************************
 *
 * Dummy printf for MS Windows DLL routine.
 *
 * Returns 0 
 *
 *****************************************************************************/
#ifdef _WINDLL
int __cdecl printf(const char *s, ...)
{
  return (0);
}
#endif /*_WINDLL*/

